package org.truenewx.tnxjee.core.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ResourceUtils;
import org.truenewx.tnxjee.core.Strings;
import org.truenewx.tnxjee.core.config.AppConstants;

/**
 * 基于当前框架的应用的工具类
 *
 * @author jianglei
 */
public class ApplicationUtil {

    /**
     * 是否通过tomcat运行，false：以一般应用的方式运行（即调用main()方法）
     */
    public static final boolean VIA_TOMCAT = System.getProperty("catalina.home") != null;
    public static final boolean IN_CODING;

    /**
     * 是否单元测试环境中
     */
    private static Boolean JUNIT_TESTING;

    private ApplicationUtil() {
    }

    static {
        try {
            Resource resource = new ClassPathResource(Strings.SLASH);
            URL url = resource.getURL();
            String classPath = url.toString().replace('\\', '/');
            IN_CODING = (!ResourceUtils.isJarURL(url))
                    && (StringUtil.antPathMatch(classPath, "**/target/**/classes/")
                    || classPath.endsWith("/target/test-classes/"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String getSymbol(Environment env) {
        return env.getProperty(AppConstants.PROPERTY_FRAMEWORK_APP_SYMBOL);
    }

    /**
     * @return 应用运行时所在的目录
     */
    public static File getWorkingDir() {
        Resource resource = new ClassPathResource(Strings.SLASH);
        try {
            if (VIA_TOMCAT) {
                if (IN_CODING) { // 编程时通过Tomcat运行
                    // 形如：**/target/[构建名称]/WEB-INF/classes
                    return resource.getFile().getParentFile().getParentFile().getParentFile();
                } else { // 构建后通过Tomcat运行
                    // 形如：**/webapps/[构建名称]/WEB-INF/classes
                    return resource.getFile().getParentFile().getParentFile().getParentFile();
                }
            } else {
                if (IN_CODING) { // 编程时以一般应用的方式运行
                    // 形如：**/target/classes
                    return resource.getFile().getParentFile();
                } else { // 构建后以一般应用的方式运行
                    String path = getWarPath(resource);
                    path = path.substring(0, path.lastIndexOf(Strings.SLASH));
                    return new File(path);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static String getWarPath(Resource resource) throws IOException {
        // 形如：jar:[file|nested]:/[目录]/*.war[!/|/!]/WEB-INF/classes/!
        String location = resource.getURL().toString().replace('\\', '/');
        location = location.substring(location.indexOf(":/") + 2, location.indexOf(Strings.EXCLAMATION));
        if (location.endsWith(Strings.SLASH)) {
            location = location.substring(0, location.length() - 1);
        }
        return location;
    }

    /**
     * @return 应用根目录
     */
    public static File getApplicationRootDir() {
        return getWorkingDir().getParentFile();
    }

    /**
     * 获取工作临时目录，与工作目录相关，非系统临时目录
     *
     * @return 工作临时目录
     */
    public static File getWorkingTempDir() {
        return new File(getApplicationRootDir(), "temp");
    }

    public static String getAbsolutePath(String path) {
        if (path.startsWith(Strings.DOT)) { // 相对路径
            File root = getApplicationRootDir();
            if (path.startsWith("./")) {
                path = root.getAbsolutePath() + IOUtil.FILE_SEPARATOR + path.substring(2);
            } else if (path.startsWith("../")) {
                path = root.getParent() + IOUtil.FILE_SEPARATOR + path.substring(3);
            } else {
                throw new RuntimeException("Invalid root path: " + path);
            }
        }
        return path;
    }

    public static File getWarFile() {
        try {
            if (IN_CODING) {
                // 从maven的pom.xml文件中读取构建目标文件
                File root = ApplicationUtil.getApplicationRootDir();
                File pomFile = new File(root, "pom.xml");
                SAXReader reader = new SAXReader();
                Document doc = reader.read(pomFile);
                Element projectElement = doc.getRootElement();
                Element buildElement = projectElement.element("build");
                String buildName = buildElement.elementTextTrim("finalName");
                String targetDirLocation = getTargetDirLocation(buildElement);
                File targetDir;
                if (targetDirLocation != null) {
                    while (targetDirLocation.startsWith("../")) {
                        targetDirLocation = targetDirLocation.substring(3);
                        root = root.getParentFile();
                    }
                    targetDir = new File(root, targetDirLocation);
                } else {
                    targetDir = getWorkingDir();
                }
                return new File(targetDir, buildName + FileExtensions.DOT_WAR);
            }
            Resource resource = new ClassPathResource(Strings.SLASH);
            if (VIA_TOMCAT) {
                // 形如：**/webapps/[构建名称]/WEB-INF/classes
                return new File(resource.getFile().getParentFile().getParent() + FileExtensions.DOT_WAR);
            } else {
                String path = getWarPath(resource);
                return new File(path);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static String getTargetDirLocation(Element buildElement) {
        Element pluginsElement = buildElement.element("plugins");
        if (pluginsElement != null) {
            List<Element> pluginElements = pluginsElement.elements("plugin");
            for (Element pluginElement : pluginElements) {
                String groupId = pluginElement.elementTextTrim("groupId");
                String artifactId = pluginElement.elementTextTrim("artifactId");
                if ("org.springframework.boot".equals(groupId) && "spring-boot-maven-plugin".equals(artifactId)) {
                    Element configurationElement = pluginElement.element("configuration");
                    return configurationElement == null ? null :
                            configurationElement.elementTextTrim("outputDirectory");
                }
            }
        }
        return null;
    }

    /**
     * @return 是否JUnit单元测试环境中
     */
    public static boolean isJunitTesting() {
        if (JUNIT_TESTING == null) {
            JUNIT_TESTING = false;
            StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
            for (int i = stackTraces.length - 1; i >= 0; i--) {
                StackTraceElement stackTrace = stackTraces[i];
                String stackString = stackTrace.toString();
                if (stackString.startsWith("org.junit.platform.")) {
                    JUNIT_TESTING = true;
                    break;
                }
            }
        }
        return JUNIT_TESTING;
    }

}
